﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CmdEditDrawProfile.h"
#include "GmUiStructureCommandRegister.h"
#include "ISelection.h"
#include "IInstance.h"
#include "IDocument.h"
#include "UserTransactionGroupUtils.h"
#include "IUserTransaction.h"
#include "StructureEditModeTypes.h"
#include "IEditMode.h"
#include "IStructureRaftFoundationEditModeBehavior.h"
#include "IStructureFloorEditModeBehavior.h"
#include "ICommandManager.h"
#include "GbmpCommandBase.h"
#include "IStructureFloor.h"
#include "IGenericElement.h"
#include "GbmpBuiltInCategoryUniIdentitiesNew.h"
#include "IStructureRaftFoundation.h"
#include "IElementPosition.h"
#include "IModelLine.h"
#include "IElement.h"
#include "IUiDocument.h"
#include "IElementTransformationComponent.h"
#include "IElementBasicInformation.h"
#include "IFamily.h"
#include "IStructurePlateHoleEditModeBehavior.h"
#include "IStructurePlateHole.h"
#include "ProfileUsedModelLineUtils.h"
#include "IElementStatus.h"
#include "IType.h"
#include "IHighlights.h"
#include "UiDocumentViewUtils.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

REGISTER_GM_COMMAND(CmdEditFloorProfile)
REGISTER_GM_COMMAND(CmdEditRaftFoundationProfile)
REGISTER_GM_COMMAND(CmdEditStructurePlateHoleProfile)

//////////////////////////////////////////////////////////////////
//CmdEditFloorProfile
CmdEditFloorProfile::CmdEditFloorProfile(const std::wstring& cmdId) : CmdEditDrawProfileBase(cmdId)
{
}

OwnerPtr<IAction> CmdEditFloorProfile::ExecuteCommand(const CommandParameters& cmdParams)
{
    IDocument*pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstance* pEditedInstance = GetSelectedInstance();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pEditedInstance != nullptr, L"未能成功获取选中的Instance！",L"GDMPLab",L"2024-03-30");
    ElementId editedId = pEditedInstance->GetElementId();

    const IFamily * pFamily = pEditedInstance->GetFamily();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFamily != nullptr, L"未能成功获取族类型！",L"GDMPLab",L"2024-03-30");

    int groupId;
    UserTransactionGroupUtils::Start(pDoc, GBMP_TR(L"绘制楼板轮廓"), groupId);
    OwnerPtr<IUserTransaction> opTransaction = IUserTransaction::Create(pDoc, GBMP_TR(L"开始绘制楼板"));

    IEditMode* pProfileEditMode = IEditMode::Get(pDoc, StructureEditModeTypes::StructureFloorEditModeType);
    if (!pProfileEditMode)
    {
        pProfileEditMode = IEditMode::Create(pDoc, IStructureFloorEditModeBehavior::Create());
    }
    DBG_WARN_AND_RETURN_UNLESS(pProfileEditMode != nullptr, nullptr, L"pProfileEditMode为空",L"GDMPLab",L"2024-03-30");

    IStructureFloorEditModeBehavior* pProfileBehavior = quick_cast<IStructureFloorEditModeBehavior>(pProfileEditMode->GetEditModeBehavior());
    DBG_WARN_AND_RETURN_UNLESS(pProfileBehavior != nullptr, nullptr, L"pProfileBehavior为空",L"GDMPLab",L"2024-03-30");

    pProfileBehavior->SetEditingFamilyId(pFamily->GetElementId());
    pProfileBehavior->SetEditingInstanceTypeId(pEditedInstance->GetBasicInformation()->GetType()->GetElementId());

    pProfileEditMode->StartEditing(pDoc, editedId, false, false);

    //设置轮廓线的可见性
    std::vector<IModelLine*> profiles;
    std::vector<IElement*> slopes;
    GetProfilesAndSlopes(editedId, profiles, slopes);

    const IElementPosition *posBehavior = pEditedInstance->GetElementPosition();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posBehavior, L"posBehavior为空",L"GDMPLab",L"2024-03-30");
    {
        //将轮廓线和坡度线从局部坐标系下变回世界坐标系下
        Matrix4d mat = posBehavior->ComputeLocalToWorldCoordinateSystemTransformMatrix();
        FOR_EACH(pProfile, profiles)
        {
            DBG_WARN_AND_CONTINUE_UNLESS(pProfile->GetOwnerElement()->GetElementTransformationComponent(), L"TransformationComponent为空",L"GDMPLab",L"2024-03-30");
            pProfile->GetOwnerElement()->GetElementTransformationComponent()->Transform(mat);
            pProfile->GetOwnerElement()->GetStatus()->SetIsVisible(true);
        }
        FOR_EACH(pSlopeElement, slopes)
        {
            DBG_WARN_AND_CONTINUE_UNLESS(pSlopeElement->GetElementTransformationComponent(), L"TransformationComponent为空",L"GDMPLab",L"2024-03-30");
            pSlopeElement->GetElementTransformationComponent()->Transform(mat);
            IElementStatus* pStatus = pSlopeElement->GetStatus();
            DBG_WARN_AND_CONTINUE_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
            pStatus->SetIsVisible(true);
        }
    }
    //设置实例的可见性
    IElementStatus* pStatus = pEditedInstance->GetStatus();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
    pStatus->SetIsVisible(false);
    opTransaction->Commit();

    // 清空选择集
    ISelection::Get()->Clear(pDoc);
    IHighlights::Get()->Clear();
    //更新文档
    UiDocumentViewUtils::GetCurrentUiDocument()->UpdateView();

    // 启动画直轮廓线的命令
    ICommandManager* pCommandManager = ICommandManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCommandManager, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    pCommandManager->SendCommand(ID_CMD_STRUCTURE_DRAW_STRAIGHT_PROFILE);

    return nullptr;
}

void CmdEditFloorProfile::GetProfilesAndSlopes(ElementId instanceId, 
    std::vector<IModelLine*>& profiles,
    std::vector<IElement*>& slopes) const
{
    IDocument*pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstance* pInstance = quick_cast<IInstance>(pDoc->GetElement(instanceId));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pInstance != nullptr, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    IStructureFloor* pFloorData = IStructureFloor::Get(pInstance);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pFloorData, L"改Instance不存在externalData!",L"GDMPLab",L"2024-03-30");

    FOR_EACH(id, pFloorData->GetProfileIds())
    {
        IModelLine* pIModelLine = nullptr;
        if (IGenericElement* pModelLineGenericElement = quick_cast<IGenericElement>(pDoc->GetElement(id)))
        {
            pIModelLine = quick_cast<IModelLine>(pModelLineGenericElement->GetExternalObject());
            if (ProfileUsedModelLineUtils::IsModelLineUsedForProfile(pIModelLine))
            {
                profiles.push_back(pIModelLine);
            }
        }
    }

    if (pFloorData->GetSlopeLineId().IsValid())
    {
        IElement* pSlopeElement = quick_cast<IElement>(pDoc->GetElement(pFloorData->GetSlopeLineId()));
        DBG_WARN_AND_RETURN_VOID_UNLESS(pSlopeElement != nullptr, L"pSlopeElement为空",L"GDMPLab",L"2024-03-30");

        slopes.push_back(pSlopeElement);
    }
}

gcmp::UniIdentity CmdEditFloorProfile::GetCategory() const
{
    UniIdentity categoryUid = BuiltInCategoryUniIdentities::BICU_STRUCTURE_FLOOR;
    return categoryUid;
}

//////////////////////////////////////////////////////////////////
//CmdEditRaftFoundationProfile
CmdEditRaftFoundationProfile::CmdEditRaftFoundationProfile(const std::wstring& cmdId): CmdEditDrawProfileBase(cmdId)
{
}

gcmp::UniIdentity CmdEditRaftFoundationProfile::GetCategory() const
{
    UniIdentity categoryUid = BuiltInCategoryUniIdentities::BICU_STRUCTURE_FOUNDATION;
    return categoryUid;
}

gcmp::OwnerPtr<gcmp::IAction> CmdEditRaftFoundationProfile::ExecuteCommand(const CommandParameters& cmdParams)
{
    IDocument*pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstance* pEditedInstance = GetSelectedInstance();
   
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pEditedInstance != nullptr, L"未能成功获取选中的Instance！",L"GDMPLab",L"2024-03-30");
    ElementId editedId = pEditedInstance->GetElementId();

    const IFamily * pFamily = pEditedInstance->GetFamily();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFamily != nullptr, L"未能成功获取族类型！",L"GDMPLab",L"2024-03-30");

    int groupId;
    UserTransactionGroupUtils::Start(pDoc, GBMP_TR(L"绘制筏板基础轮廓"), groupId);
    OwnerPtr<IUserTransaction> opTransaction = IUserTransaction::Create(pDoc, GBMP_TR(L"开始绘制筏板基础"));

    IEditMode* pProfileEditMode = IEditMode::Get(pDoc, StructureEditModeTypes::StructureRaftFoundationEditModeType);
    if (!pProfileEditMode)
    {
        pProfileEditMode = IEditMode::Create(pDoc, IStructureRaftFoundationEditModeBehavior::Create());
    }
    DBG_WARN_AND_RETURN_UNLESS(pProfileEditMode != nullptr, nullptr, L"pProfileEditMode为空",L"GDMPLab",L"2024-03-30");
    IStructureRaftFoundationEditModeBehavior* pProfileBehavior = quick_cast<IStructureRaftFoundationEditModeBehavior>(pProfileEditMode->GetEditModeBehavior());
    DBG_WARN_AND_RETURN_UNLESS(pProfileBehavior != nullptr, nullptr, L"pProfileBehavior为空",L"GDMPLab",L"2024-03-30");
    pProfileBehavior->SetEditingFamilyId(pFamily->GetElementId());
    pProfileBehavior->SetEditingInstanceTypeId(pEditedInstance->GetBasicInformation()->GetType()->GetElementId());

    pProfileEditMode->StartEditing(pDoc, editedId, false, false);

    //设置轮廓线的可见性
    std::vector<IModelLine*> profiles;
    GetProfiles(editedId, profiles);

    const IElementPosition *posBehavior = pEditedInstance->GetElementPosition();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posBehavior, L"posBehavior为空",L"GDMPLab",L"2024-03-30");
    {
        //将轮廓线从局部坐标系下变回世界坐标系下
        Matrix4d mat = posBehavior->ComputeLocalToWorldCoordinateSystemTransformMatrix();
        FOR_EACH(pProfile, profiles)
        {
            DBG_WARN_AND_CONTINUE_UNLESS(pProfile->GetOwnerElement()->GetElementTransformationComponent(), L"TransformationComponent为空",L"GDMPLab",L"2024-03-30");
            pProfile->GetOwnerElement()->GetElementTransformationComponent()->Transform(mat);
            pProfile->GetOwnerElement()->GetStatus()->SetIsVisible(true);
        }
    }
    //设置实例的可见性
    IElementStatus* pStatus = pEditedInstance->GetStatus();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
    pStatus->SetIsVisible(false);
    opTransaction->Commit();

    // 清空选择集
    ISelection::Get()->Clear(pDoc);
    IHighlights::Get()->Clear();
    //更新文档
    UiDocumentViewUtils::GetCurrentUiDocument()->UpdateView();

    // 启动画直轮廓线的命令
    ICommandManager* pCommandManager = ICommandManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCommandManager, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    pCommandManager->SendCommand(ID_CMD_STRUCTURE_DRAW_STRAIGHT_PROFILE);

    return nullptr;
}

void CmdEditRaftFoundationProfile::GetProfiles(ElementId instanceId, std::vector<IModelLine*>& profiles) const
{
    IDocument*pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstance* pInstance = quick_cast<IInstance>(pDoc->GetElement(instanceId));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pInstance != nullptr, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    IStructureRaftFoundation* pFoundationData = IStructureRaftFoundation::Get(pInstance);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pFoundationData, L"改Instance不存在externalData!",L"GDMPLab",L"2024-03-30");

    FOR_EACH(id, pFoundationData->GetProfileIds())
    {
        IModelLine* pIModelLine = nullptr;
        if (IGenericElement* pModelLineGenericElement = quick_cast<IGenericElement>(pDoc->GetElement(id)))
        {
            pIModelLine = quick_cast<IModelLine>(pModelLineGenericElement->GetExternalObject());
            if (ProfileUsedModelLineUtils::IsModelLineUsedForProfile(pIModelLine))
            {
                profiles.push_back(pIModelLine);
            }
        }
    }
}

//////////////////////////////////////////////////////////////////
//CmdEditStructurePlateHoleProfile
gcmp::CmdEditStructurePlateHoleProfile::CmdEditStructurePlateHoleProfile(const std::wstring& cmdId) : CmdEditDrawProfileBase(cmdId)
{
}

gcmp::OwnerPtr<gcmp::IAction> gcmp::CmdEditStructurePlateHoleProfile::ExecuteCommand(const CommandParameters& cmdParams)
{
    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstance* pEditedInstance = GetSelectedInstance();

    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pEditedInstance != nullptr, L"未能成功获取选中的Instance！",L"GDMPLab",L"2024-03-30");
    ElementId editedId = pEditedInstance->GetElementId();

    const IFamily * pFamily = pEditedInstance->GetFamily();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFamily != nullptr, L"未能成功获取族类型！",L"GDMPLab",L"2024-03-30");

    int groupId;
    UserTransactionGroupUtils::Start(pDoc, GBMP_TR(L"绘制板洞轮廓"), groupId);
    OwnerPtr<IUserTransaction> opTransaction = IUserTransaction::Create(pDoc, GBMP_TR(L"开始绘制板洞轮廓"));

    IEditMode* pStructurePlateHoleEditMode = IEditMode::Get(pDoc, StructureEditModeTypes::StructurePlateHoleModeType);
    if (!pStructurePlateHoleEditMode)
    {
        pStructurePlateHoleEditMode = IEditMode::Create(pDoc, IStructurePlateHoleEditModeBehavior::Create());
    }
    DBG_WARN_AND_RETURN_UNLESS(pStructurePlateHoleEditMode != nullptr, nullptr, L"pProfileEditMode为空",L"GDMPLab",L"2024-03-30");
    IStructurePlateHoleEditModeBehavior* pProfileBehavior = quick_cast<IStructurePlateHoleEditModeBehavior>(pStructurePlateHoleEditMode->GetEditModeBehavior());
    DBG_WARN_AND_RETURN_UNLESS(pProfileBehavior != nullptr, nullptr, L"pProfileBehavior为空",L"GDMPLab",L"2024-03-30");
    pProfileBehavior->SetEditingFamilyId(pFamily->GetElementId());
    pProfileBehavior->SetEditingInstanceTypeId(pEditedInstance->GetBasicInformation()->GetType()->GetElementId());
    pStructurePlateHoleEditMode->StartEditing(pDoc, editedId, false, false);

    //设置轮廓线的可见性
    std::vector<IModelLine*> profiles;
    GetProfiles(editedId, profiles);

    const IElementPosition *posBehavior = pEditedInstance->GetElementPosition();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(posBehavior, L"posBehavior为空",L"GDMPLab",L"2024-03-30");
    {
        //将轮廓线从局部坐标系下变回世界坐标系下
        Matrix4d mat = posBehavior->ComputeLocalToWorldCoordinateSystemTransformMatrix();
        FOR_EACH(pProfile, profiles)
        {
            DBG_WARN_AND_CONTINUE_UNLESS(pProfile->GetOwnerElement()->GetElementTransformationComponent(), L"TransformationComponent为空",L"GDMPLab",L"2024-03-30");
            pProfile->GetOwnerElement()->GetElementTransformationComponent()->Transform(mat);
            pProfile->GetOwnerElement()->GetStatus()->SetIsVisible(true);
        }
    }
    //设置实例的可见性
    IElementStatus* pStatus = pEditedInstance->GetStatus();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
    pStatus->SetIsVisible(false);
    opTransaction->Commit();

    // 清空选择集
    ISelection::Get()->Clear(pDoc);
    IHighlights::Get()->Clear();
    //更新文档
    UiDocumentViewUtils::GetCurrentUiDocument()->UpdateView();

    // 启动画直轮廓线的命令
    ICommandManager* pCommandManager = ICommandManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pCommandManager, L"pInstance为空",L"GDMPLab",L"2024-03-30");
    pCommandManager->SendCommand(ID_CMD_STRUCTURE_DRAW_STRAIGHT_PROFILE);

    return nullptr;
}

gcmp::UniIdentity gcmp::CmdEditStructurePlateHoleProfile::GetCategory() const
{
    UniIdentity categoryUid = BuiltInCategoryUniIdentities::BICU_STRUCTURE_PLATE_HOLE;
    return categoryUid;
}

void gcmp::CmdEditStructurePlateHoleProfile::GetProfiles(ElementId instanceId, std::vector<IModelLine*>& profiles) const
{
    IDocument*pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    IInstance* pInstance = quick_cast<IInstance>(pDoc->GetElement(instanceId));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pInstance != nullptr, L"pInstance为空",L"GDMPLab",L"2024-03-30");

    IStructurePlateHole* pPlateHole = IStructurePlateHole::Get(pInstance);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pPlateHole, L"获取板洞数据失败",L"GDMPLab",L"2024-03-30");

    std::vector<ElementId> profileIds = pPlateHole->GetProfileIds();
    DBG_WARN_AND_RETURN_VOID_UNLESS(!profileIds.empty(), L"profileIds为空",L"GDMPLab",L"2024-03-30");
    
    FOR_EACH(id, profileIds)
    {
        IModelLine* pIModelLine = nullptr;
        if (IGenericElement* pGenericElement = quick_cast<IGenericElement>(pDoc->GetElement(id)))
        {
            pIModelLine = quick_cast<IModelLine>(pGenericElement->GetExternalObject());
            if (ProfileUsedModelLineUtils::IsModelLineUsedForProfile(pIModelLine))
            {
                profiles.push_back(pIModelLine);
            }
        }
    }
}
